#include <pthread.h>
#include <vector>
#include <string>
#include <functional>
#include <queue>
#include <unistd.h>
#include <atomic>
#include "log.hpp"

class threadInfo
{
public:
    pthread_t tid;
    std::string name;
};

template<class T>
class threadPool
{
public:
    threadPool(int n)
    : _threads(n)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);

        for (int i = 0; i < n; i++)
        {
            pthread_create(&(_threads[i].tid), nullptr, handTask, this);
        }
    }

    void push(std::function<T> _task) //加入任务
    {
        pthread_mutex_lock(&_mutex);
        _tasks.push(_task);
        pthread_mutex_unlock(&_mutex);
        pthread_cond_signal(&_cond);
    }

    ~threadPool()
    {
        check = false;
        pthread_cond_broadcast(&_cond);

        for (int i = 0; i < _threads.size(); i++)
        {
            pthread_join(_threads[i].tid, nullptr);
        }
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    static void* handTask(void* args)
    {
        threadPool<T>* th = static_cast<threadPool<T>*>(args); 
        while (th->check)
        {
            std::function<T> t = th->pop();
            if (t)
            {
                t();
            }
        }
        return nullptr;
    }

    std::function<T> pop() // 取出队头任务
    {
        pthread_mutex_lock(&(_mutex)); //加锁，一次只能一个线程进入
        while (_tasks.empty() && check)
        {
            pthread_cond_wait(&_cond, &_mutex);
        }
        if (!check)
        {
            pthread_mutex_unlock(&_mutex);
            return nullptr;
        }
        std::function<T> _task = _tasks.front();
        _tasks.pop();
        pthread_mutex_unlock(&_mutex);
        return _task;
    }
private:
    std::vector<threadInfo> _threads;
    std::queue<std::function<T>> _tasks;

    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    std::atomic<bool> check = true;
};